上篇提到的prettyjson工具,经我改写之后,可以JavaScript对象格式输出缩进排版的JSON格式。如下所示:

var prettyjson = require('prettyjson');

var data = {
  username: 'rafeca',
  url: 'https://github.com/rafeca',
  twitter_account: 'https://twitter.com/rafeca',
  projects: ['prettyprint', 'connfu'],
};
console.log(prettyjson.render(data, options));

输出:

{
  "username": "rafeca",
  "url": "https://github.com/rafeca",
  "twitter_account": "https://twitter.com/rafeca",
  "projects": [
    "prettyprint",
    "connfu"
  ]
}

我不记得这中间遇到多少坑了。
将JSON对象格式化输出大致的思路是利用递归的方式,将中结果保存到数组,然后一次性输出。
1.判断data是否是对象,如果是则保存(push)'当前缩进空格+{',中间结果和'当前缩进空格+{,',将'当前缩进空格+{,'保存到数组(output)前将当前数组(output)的最后一个元素的末尾逗号删除。

  • 判断中间结果是否是可以直接序列化的,若是,序列化保存到数组(output)
  • 不是则递归下去
if (typeof data === 'object') {
    /*一开始时当前缩进为0,所以可以输出最外一层对齐的 { 和 } */
    var line = indent(indentation); 
    output.push(line+'{');
    var key;
    var isError = data instanceof Error;
    indentation = indentation + options.defaultIndentation;
    Object.getOwnPropertyNames(data).forEach(function(i) {
      // Prepend the index at the beginning of the line
      key = ('"' + i +'"'+ ': ');
      key = indent(indentation) + key;

      // Skip `undefined`, it's not a valid JSON value.
      if (data[i] === undefined) {
        return;
      }
    /*可以直接序列化的,拼接到"key": 即可,后面仍有逗号*/
      if(isSerializable(data[i])) {
        output.push(key + outputData(data[i]) + ',');
      }else {
        /* 递归,注意render的结果是字符串,开始位置有缩进,
        *  所以拼接到key: 后面时需要trim掉
        */
        var temp = exports.render(data[i], options, indentation);
        output.push(key + temp.trim() + ',');
      }
    });
    removeLastComma(output);
    output.push(line + '},');
}

2.判断是否是数组,如果是则保存(push)'当前缩进空格+[',中间结果和'当前缩进空格+],',将'当前缩进空格+],'保存到数组(output)前将当前数组(output)的最后一个元素的末尾逗号删除。

  • 判断中间结果是否可以直接序列化,若是,则序列化保存到数组(output)
  • 不是则递归下去
if (Array.isArray(data)) {
    var line = indent(indentation);
    indentation = indentation + options.defaultIndentation;
    output.push(line + '[');
    // If the array is empty
    if (data.length === 0) {
      output.push(indent(indentation) +' ');
    } else {
      data.forEach(function(element) {
        /* 可以直接序列化的情况*/
        if(isSerializable(element)) {
            output.push(indent(indentation) + outputData(element) + ',');
        }else {
           /* 递归 */
           var temp = exports.render(data[i], options, indentation);
           output.push(key + temp.trim() + ',');
        }
      });
      removeLastComma(output);
    }
    output.push(line + '],');
  }

3.辅助函数,判断是否可以直接序列化(boolean, number, string, null)

var isSerializable = function(input, onlyPrimitives) {
    if (typeof input === 'boolean' ||
        typeof input === 'number' || input === null) {
      return true;
    }
    if (typeof input === 'string' && input.indexOf('\n') === -1) {
      return true;
    }

    return false;
  };

4.辅助函数,输出字符和其他类型

 var outputData = function(input) {

    if (typeof input === 'string') {
      // Print strings wraped by double quote
      return '"' + input + '"';
    }

    if (input === true) {
      return 'true';
    }
    if (input === false) {
      return 'false';
    }
    if (input === null) {
      return '';
    }
    if (typeof input === 'number') {
      return input;
    }

    return input;
  };

5.主函数

exports.render = function(data, options, indentation) {
  indentation = indentation || 0;
  options = options || {};
  options.defaultIndentation = options.defaultIndentation || 2;

  var output = []; //合并所有中间结果的数组
  removeLastComma(output); //删除最后一个逗号
  // Return all the lines as a string
  return output.join('\n');
}

6.renderstring函数将字符串反序列成对象然后再调用render方法格式化、序列化。


Honwhy
7k 声望96 粉丝

神兽党有福了